home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
shells
/
bashsrc.zoo
/
execute_cmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
44KB
|
1,684 lines
/* execute_command.c -- Execute a COMMAND structure. */
/* Copyright (C) 1989 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#ifndef SONY
#include <fcntl.h>
#endif
#include <sys/file.h>
#include <sys/stat.h>
#include <signal.h>
#ifndef SIGABRT
#define SIGABRT SIGIOT
#endif
#include <sys/param.h>
#include <errno.h>
#include "shell.h"
#include "y.tab.h"
#include "builtins.h"
#include "flags.h"
#include "hash.h"
#ifdef JOB_CONTROL
#include "jobs.h"
#endif
#ifdef ALIAS
#include "alias.h"
#endif
extern int breaking, continuing, loop_level;
extern int errno, sys_nerr;
extern char *sys_errlist[];
#ifdef SYSV
extern int last_made_pid;
#endif
extern WORD_LIST *expand_words (), *expand_word ();
/* The value returned by the last synchronous command. */
int last_command_exit_value = 0;
/* The list of redirections to preform which will undo the redirections
that I made in the shell. */
REDIRECT *redirection_undo_list = (REDIRECT *)NULL;
/* Execute the command passed in COMMAND. COMMAND is exactly what
read_command () places into GLOBAL_COMMAND. See "shell.h" for the
details of the command structure.
EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible
return values. Executing a command with nothing in it returns
success. */
execute_command (command)
COMMAND *command;
{
/* Just do the command, but not asynchronously. */
return (execute_command_internal (command, 0, NO_PIPE, NO_PIPE));
}
/* Returns 1 if TYPE is a shell control structure type. */
int
shell_control_structure (type)
enum command_type type;
{
switch (type)
{
case cm_for:
case cm_case:
case cm_while:
case cm_until:
case cm_if:
case cm_group:
return (1);
default:
return (0);
}
}
execute_command_internal (command, asynchronous, pipe_in, pipe_out)
COMMAND *command;
int asynchronous;
int pipe_in, pipe_out;
{
int exec_result;
REDIRECT *my_undo_list = (REDIRECT *)NULL;
if (!command || breaking || continuing)
return (EXECUTION_SUCCESS);
/* If a command was being explicitly run in a subshell, or if it is
a shell control-structure, and it has a pipe, then we do the command
in a subshell. */
if (command->subshell ||
(shell_control_structure (command->type) &&
(pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous)))
{
int paren_pid;
/* Fork a subshell, turn off the subshell bit, turn off job
control and call execute_command () on the command again. */
paren_pid = make_child (savestring (make_command_string (command)),
asynchronous);
if (paren_pid == 0)
{
extern int interactive, login_shell;
command->subshell = 0;
/* Don't fork again, we are already in a subshell. */
asynchronous = 0;
/* Subshells are neither login nor interactive. */
login_shell = interactive = 0;
#ifdef JOB_CONTROL
/* Delete all traces that there were any jobs running. This is
only for subshells. */
without_job_control ();
#endif
do_piping (pipe_in, pipe_out);
if (command->redirects)
if (!(do_redirections (command->redirects, 1, 0) == 0))
exit (EXECUTION_FAILURE);
exit (execute_command_internal
(command, asynchronous, NO_PIPE, NO_PIPE));
}
else
{
close_pipes (pipe_in, pipe_out);
/* If we are part of a pipeline, and not the end of the pipeline,
then we should simply return and let the last command in the
pipe be waited for. If we are not in a pipeline, or are the
last command in the pipeline, then we wait for the subshell
and return its exit status as usual. */
if (pipe_out != NO_PIPE)
return (EXECUTION_SUCCESS);
stop_pipeline (asynchronous, (COMMAND *)NULL);
if (!asynchronous)
return (last_command_exit_value = wait_for (paren_pid));
else
{
extern int interactive;
if (interactive)
describe_pid (paren_pid);
return (EXECUTION_SUCCESS);
}
}
}
/* Handle WHILE FOR CASE etc. with redirections. (Also '&' input
redirection.) */
do_redirections (command->redirects, 1, 1);
my_undo_list = (REDIRECT *)copy_redirects (redirection_undo_list);
switch (command->type)
{
case cm_for:
exec_result = execute_for_command (command->value.For);
break;
case cm_case:
exec_result = execute_case_command (command->value.Case);
break;
case cm_while:
exec_result = execute_while_command (command->value.While);
break;
case cm_until:
exec_result = execute_until_command (command->value.While);
break;
case cm_if:
exec_result = execute_if_command (command->value.If);
break;
case cm_group:
if (asynchronous)
{
command->subshell = 1;
exec_result =
execute_command_internal (command, 1, pipe_in, pipe_out);
}
else
{
exec_result =
execute_command_internal (command->value.Group->command,
asynchronous, pipe_in, pipe_out);
}
break;
case cm_simple:
{
extern int last_asynchronous_pid, last_made_pid;
int last_pid = last_made_pid;
#ifdef JOB_CONTROL
extern int already_making_children;
#endif
exec_result =
execute_simple_command (command->value.Simple, pipe_in, pipe_out,
asynchronous);
/* If we forked to do the command, then we must
wait_for() the child. */
#ifdef JOB_CONTROL
if (already_making_children && pipe_out == NO_PIPE)
#else
if (pipe_out == NO_PIPE)
#endif
{
if (last_pid != last_made_pid)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
if (asynchronous)
{
extern int interactive;
if (interactive)
describe_pid (last_made_pid);
}
else
exec_result = wait_for (last_made_pid);
}
}
}
break;
case cm_connection:
switch (command->value.Connection->connector)
{
/* Do the first command asynchronously. */
case '&':
{
COMMAND *tc = command->value.Connection->first;
#ifndef JOB_CONTROL
{
REDIRECT *tr =
make_redirection (0, r_inputa_direction,
make_word ("/dev/null"));
tr->next = tc->redirects;
tc->redirects = tr;
}
#endif /* !JOB_CONTROL */
exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out);
if (command->value.Connection->second)
exec_result =
execute_command_internal (command->value.Connection->second,
asynchronous, pipe_in, pipe_out);
}
break;
case ';':
/* Just call execute command on both of them. */
execute_command (command->value.Connection->first);
exec_result =
execute_command_internal (command->value.Connection->second,
asynchronous, pipe_in, pipe_out);
break;
case '|':
{
/* Make a pipeline between the two commands. */
int fildes[2];
if (pipe (fildes) < 0)
{
report_error ("Pipe error %d", errno);
exec_result = EXECUTION_FAILURE;
}
else
{
execute_command_internal (command->value.Connection->first,
asynchronous, pipe_in, fildes[1]);
exec_result =
execute_command_internal (command->value.Connection->second,
asynchronous,